package com.tarry.socket.blocked;

import lombok.extern.slf4j.Slf4j;

import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;

/**
 * 阻塞式
 */
@Slf4j
public class Server {

    private final static int DEFAULT_PORT = 3333;
    private int port;

    public Server(){
        this.port = DEFAULT_PORT;
    }

    public Server(int port) {
        this.port = port;
    }

    public void start() throws Exception {
        final ServerSocket socket = new ServerSocket(this.port);
        log.info("start server, listen port:{}",this.port);
//      创建可缓存到线程池，不限制线程到数量，根据任务数量产生对应数量到线程，创建到线程被缓存起来，可重复使用，主要用于处理突发流量
//       核心线程数 0,
//       最大线程数 Integer.MAX_VALUE,
//       线程存活时间 60L,
//       TimeUnit.SECONDS,
//       阻塞队列-生产消费者模式，无存储容器 new SynchronousQueue<Runnable>()
        final ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
        while (true) {
            // 调用accept方法阻塞，直到有新的请求进入
            final Socket accept = socket.accept();
            log.info("get the new request: {}", accept.getInetAddress());
//          将请求托管到线程池
            cachedThreadPool.execute(() -> {
                handle(accept);
            });
        }
    }

    public void handle(Socket socket) {
        try {
            final InputStream inputStream = socket.getInputStream();
            log.info("{}:{} :get msg ~~~ ", socket.getInetAddress(), socket.getPort());
            final DataInputStream dataInputStream = new DataInputStream(inputStream);
            /**
             * 数据包格式 4位数据长度 + 实际数据
             */
            while (true) { // 循环读取发送来的数据+++++++++++++++++++++-**-
                while (dataInputStream.available() > 0) {
                    final int length = dataInputStream.readInt();
                    log.info("data length:{}", length);
                    byte[] data = new byte[length];
                    dataInputStream.read(data);
                    log.info(new String(data));
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws Exception{
        final Server server = new Server();
        server.start();
    }
}
